GM.Name 	= "Winter Survival"
GM.Author 	= "Night-Eagle & Termy58" //word
GM.Email 	= "gmail sedhdi"
GM.Website 	= ""

// Decay measured in percent per second
// Decay constants

GM.decay = {
	cold = 100/180,
	thirst = 100/240,
	hunger = 100/480,
	fatigue = -100/90,
	constitution = -100/60,
}

GM.buff = {
	campfire_radius = 256,
	campfire_cold = -100/30, //The player is in the fire (0 Distance)
	drinkrate = -100/5, //Drink water
}

wsNet = {}
wsNet.CROUCH = 1

//Text to show in the server browser
function GM:GetGameDescription()
	return self.Name
end

function GM:Initialize()
	self:ParseItems()
	if self.Initialized then
		self:Initialized()
	end
end

function GM:Saved()
end

function GM:Restored()
end

function GM:DoDecay(delta)
	local tab
	
	if SERVER then
		tab = player.GetAll()
	else
		tab = {
			LocalPlayer(),
		}
		local deathrate;
	end
	
	for k,pl in pairs(tab) do
		local needstab
		if SERVER then
			needstab = self.needs[pl]
		else
			needstab = self.needs
		end
		if (SERVER and self.net[pl] or CLIENT) and needstab and pl:Alive() and not pl:WSIsPigeon() then //Duplicity Init hook PlayerDeath
			local speed = pl:GetVelocity():Length()
			
			if SERVER then
				if pl:Crouching() ~= self.net[pl][wsNet.CROUCH] then
					self.net[pl][wsNet.CROUCH] = pl:Crouching()
					self:sendNet(pl)
				end
			end
			for decay,rate in pairs(self.decay) do //for all decays
				if needstab then
					if decay == "cold" then
						rate = rate + math.max(0,pl:WaterLevel()-1)*2^4*rate*.75
						if self:crouching(pl) then
							rate = rate * .75
						end
						
						rate = rate*(speed/250+1)
						
						//Campfire
						local total = 0
						for k,v in pairs(ents.FindByClass("ws_campfire")) do
							local mod = (v:GetPos()-pl:GetShootPos()):Length()
							mod = math.Clamp(1 - mod/self.buff.campfire_radius,0,1)
							mod = mod*self.buff.campfire_cold
							total = total + mod
						end
						total = math.max(total,1.5*self.buff.campfire_cold) //Maximum of 1.5 times full effect (Generous)
						rate = rate + total
					elseif decay == "fatigue" then
						rate = rate + math.max(0,speed-175)*5*.01
						if self:crouching(pl) and speed < 20 then
							rate = rate - 500*.01
						end
						//pl:SendLua("debuga = "..math.Clamp(needstab[decay] + rate*delta,0,100))
					elseif decay == "constitution" then
						local constitutionrate = false
						for k, v in pairs(needstab)  do
							if k != "constitution" then
								if v >= 95 then
									constitutionrate = true
								end
							end
						end
						if !constitutionrate then rate = 0 end
					elseif decay == "thirst" then
						if pl:KeyDown(IN_USE) then
							local tr = util.TraceLine{
								start = pl:GetShootPos(),
								endpos = pl:GetShootPos() + pl:EyeAngles():Forward()*170,
								filter = pl,
								mask = MASK_WATER,
							}
							local tra = util.TraceLine{
								start = pl:GetShootPos(),
								endpos = pl:GetShootPos() + pl:EyeAngles():Forward()*170,
								filter = pl,
							}
							if tr.Hit and tra.Fraction - .001 >= tr.Fraction then
								rate = self.buff.drinkrate
							end
						end
					end
					
					needstab[decay] = math.Clamp(needstab[decay] + rate*delta,0,100)
					if CLIENT then
						deathrate = deathrate or {}
						deathrate[decay] = rate
					end
					
					if SERVER then
						self.updateNeeds(pl)
						
						if needstab.constitution <= 0 then
							local fail = false
							for k,v in pairs(self.buildingdata) do
								if v.Owner == pl and v.class == "corpse" then //WARNING: This code means the game can work ONLY AS INTENDED. One player spawn per round, otherwise they are invincible.
									fail = true
								end
							end
							
							if not fail then
								
								pl:Kill()//Silent()
								//corpse:SetOwner()
								//Msg(tab.wsUID,"\n")
								//Msg(corpse:GetTable().wsUID,"\n")
							end
						end
					end
				end
			end
		end
	end
	if CLIENT && deathrate then //Lets see how much longer this biznitch has to live
		local highriskfact;
		local risk;
		local needleft;
		
		//This is why we need to use brackets for self.needs
		
		needleft = 100 - self.needs.hunger
		risk = needleft / deathrate["hunger"] //seconds till const
		highriskfact = risk
		
		needleft = 100 - self.needs.thirst
		risk = needleft / deathrate["thirst"]
		if risk < highriskfact then
			highriskfact = risk
		end
		
		needleft = 100 - self.needs.fatigue
		risk = needleft / deathrate["fatigue"]
		if risk < highriskfact then
			highriskfact = risk
		end
		
		needleft = 100 - self.needs.cold
		risk = needleft / deathrate["cold"]
		if risk < highriskfact then
			highriskfact = risk
		end
		
		if constitutionrate then
			local constleft = 100 - self.needs.constitution / deathrate["constitution"]
			highriskfact = highriskfact + constleft
		else
		//TODO
		/*
			make it so it calculates the user generated time left
			instead of the current pre-mediated 60 seconds constitution
		*/
			highriskfact = highriskfact + 60
		end
		self.DeathClock = highriskfact
	end
end

//Macros

function GM:TraceValidBuild( tr, pl )
	//TERMY: Use this instead:
	/*
	local ang = tr.HitNormal:Angle()
	if ang.p > 30 or ang.r > 30 then
		return false
	end
	*/
	if tr.HitNormal.x > 0.3 or tr.HitNormal.y > 0.3 or tr.HitNormal.z < 0.5 then
		return false
	end
	
	/*
	if pl:GetPos():Distance( tr.HitPos ) < 45 then
		return false
	end
	*/
	
	for k,v in pairs(player.GetAll()) do
		if v:GetPos():Distance(tr.HitPos) < 72 then
			return false
		end
	end
	
	local tra = util.TraceLine{
	start = pl:GetShootPos(),
	endpos = pl:GetShootPos() + pl:EyeAngles():Forward()*170,
	filter = pl,
	mask = MASK_WATER,
	}
	
	if tra.Hit and tr.Fraction - .001 >= tra.Fraction then
		return false,false
	end
	
	if !tr.HitWorld then
		if tr.Entity:GetClass() == "func_physbox_multiplayer" then
			return true,tr.Entity
		end
		return false,false
	end
	
	return true,false
end

function GM.IsDamageableClass(class)
	if type(class) == "string" and (
		class == "player" or
		class:sub(1,4) == "npc_" or
		class == "ws_pigeon"
	) then
		return true
	end
	return false
end

function GM.IsTreeModel(model)
	//models/props_foliage/tree_deciduous_01a.mdl
	
	if type(model) == "string" and (
		string.find(model,"tree")
	) then
		return true
	end
	return false
end


























